package com.hk.stream.rocketmq.appender.log4j2;

import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
import org.apache.logging.log4j.core.layout.JsonLayout;

import java.io.Serializable;
import java.util.Objects;

/**
 * @author Kevin
 * @date 2023-05-14 20:07
 */
@Plugin(name = "RocketMQ",
        category = Node.CATEGORY,
        elementType = Appender.ELEMENT_TYPE,
        printObject = true)
public class RocketmqLog4j2Appender extends AbstractAppender {

    private final RocketMqSender rocketMqSender;

    protected RocketmqLog4j2Appender(String name, Filter filter, Layout<? extends Serializable> layout,
                                     boolean ignoreExceptions,
                                     String topic,
                                     String host, String source, String index,
                                     int maxEventsBatchCount,
                                     String communicationMode,
                                     long delay,
                                     Property[] properties) {
        super(name, filter, layout, ignoreExceptions, properties);
        rocketMqSender = new RocketMqSender(topic, host, source, index, maxEventsBatchCount, communicationMode, delay);
    }


    @Override
    public void append(LogEvent event) {
        String msg = getLayout().toSerializable(event).toString();
        rocketMqSender.send(event.getLevel().toString(), msg, event.getLoggerName(), event.getThreadName(),
                Objects.isNull(event.getThrown()) ? null : event.getThrown().getMessage());
    }

    @Override
    public void stop() {
        this.rocketMqSender.close();
        super.stop();
    }

    @PluginBuilderFactory
    public static Builder newBuilder() {
        return new Builder();
    }

    public static class Builder implements org.apache.logging.log4j.core.util.Builder<RocketmqLog4j2Appender> {

        @PluginBuilderAttribute
        @Required(message = "A name for the RocketmqLog4j2Appender must be specified")
        private String name;

        @PluginElement("Layout")
        private Layout<? extends Serializable> layout;

        @PluginElement("Filter")
        private Filter filter;

        @PluginBuilderAttribute
        private boolean ignoreExceptions;

        @PluginBuilderAttribute
        @Required(message = "A topic name must be specified")
        private String topic;

        @PluginBuilderAttribute
        private String host;

        @PluginBuilderAttribute
        private String source;

        @PluginBuilderAttribute
        private String index;

        @PluginBuilderAttribute
        private int maxEventsBatchCount;

        @PluginBuilderAttribute
        private String communicationMode;

        /**
         * 单位: 毫秒
         */
        @PluginBuilderAttribute
        private long delay;

        private Builder() {
            this.layout = JsonLayout.createDefaultLayout();
            this.ignoreExceptions = true;
        }

        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        public Builder setLayout(Layout<? extends Serializable> layout) {
            this.layout = layout;
            return this;
        }

        public Builder setFilter(Filter filter) {
            this.filter = filter;
            return this;
        }

        public Builder setIgnoreExceptions(boolean ignoreExceptions) {
            this.ignoreExceptions = ignoreExceptions;
            return this;
        }

        public Builder setTopic(final String topic) {
            this.topic = topic;
            return this;
        }

        public Builder setHost(final String host) {
            this.host = host;
            return this;
        }

        public Builder setSource(final String source) {
            this.source = source;
            return this;
        }

        public Builder setIndex(final String index) {
            this.index = index;
            return this;
        }

        public Builder setMaxEventsBatchCount(int maxEventsBatchCount) {
            this.maxEventsBatchCount = maxEventsBatchCount;
            return this;
        }

        public Builder setCommunicationMode(String communicationMode) {
            this.communicationMode = communicationMode;
            return this;
        }

        public Builder setDelay(long delay) {
            this.delay = delay;
            return this;
        }

        public RocketmqLog4j2Appender build() {
            return new RocketmqLog4j2Appender(name, filter, layout, ignoreExceptions,
                    topic, host, source, index, maxEventsBatchCount, communicationMode, delay, new Property[0]);
        }
    }
}
